package com.love.rongcommon.config.advice;

import com.google.common.collect.Lists;
import com.love.rongcommon.base.response.BaseResponse;
import com.love.rongcommon.exception.BaseException;
import com.love.rongcommon.exception.BusinessException;
import com.love.rongcommon.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@RestControllerAdvice
public class GlobalHandlerAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 防止业务二次封装
        if (body instanceof BaseResponse || body instanceof ResultVo) {
            return body;
        }

        // 组装返回结果
        return new ResultVo(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), body);
    }

    /**
     * 参数异常捕获
     */
    @ExceptionHandler(value = {BindException.class})
    public ResultVo bindException(BindException e) {
        log.info("bindException has been invoked", e);
        return new ResultVo(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), getMsg(e.getBindingResult()));
    }

    /**
     * 参数异常捕获
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResultVo methodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.info("methodArgumentNotValidException has been invoked", e);
        return new ResultVo(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), getMsg(e.getBindingResult()));
    }

    /**
     * 业务异常捕获
     */
    @ExceptionHandler(value = {BusinessException.class, BaseException.class})
    public ResultVo businessException(BaseException e) {
        log.info("businessException has been invoked", e);
        return new ResultVo(e.getCode(), e.getMsg());
    }

    /**
     * 系统异常捕获
     */
    @ExceptionHandler(value = {Exception.class})
    public ResultVo exception(Exception e) {
        log.info("exception has been invoked", e);
        return new ResultVo(HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
    }

    /**
     * 提取参数异常信息
     *
     * @param bindingResult
     * @return
     */
    private List<String> getMsg(BindingResult bindingResult) {
        ArrayList<String> list = Lists.newArrayList();
        bindingResult.getFieldErrors().forEach(item -> {
            String errorField = item.getField();
            String errorMessage = item.getDefaultMessage();
            list.add(errorField + errorMessage);
        });
        return list;
    }
}
